package com.ease.common.util;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;

import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.type.TypeReference;

/**
 * 
 * @author nathanleewei
 * 
 */
public abstract class JsonUtil {

	private static final ObjectMapper objectMapper = new ObjectMapper();

	static {

		// org.codehaus.jackson.map.JsonMappingException: No serializer found
		// for class $Proxy139 and no properties
		// discovered to create BeanSerializer (to avoid exception, disable
		// SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference
		// chain:
		// com.irm.model.business.Number["extension"]->com.irm.model.Extension[
		// "attributes"]->com.irm.type.
		// ExtensionAttributeMap["metaShelfAccessService"])
		// at org.codehaus.jackson.map.ser.StdSerializerProvider$1.serialize(
		// StdSerializerProvider.java:55)
		// at org.codehaus.jackson.map.ser.MapSerializer.serializeEntries(
		// MapSerializer.java:131)
		// at
		// org.codehaus.jackson.map.ser.MapSerializer.serialize(MapSerializer.
		// java:74)

		objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
		// objectMapper.conf
	}

	// http://www.codeweblog.com/when-using-the-jackson-json-conversion-the-date-
	// format-settings/
	// static {
	// objectMapper.configure(SerializationConfig.Feature.
	// WRITE_DATES_AS_TIMESTAMPS,
	// false);
	// objectMapper.getSerializationConfig().setDateFormat(myDateFormat);// not
	// thread safe
	// }

	public static String marshal(Object object) {

		StringWriter writer = new StringWriter();
		try {
			objectMapper.writeValue(writer, object);
		} catch (JsonGenerationException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		} catch (JsonMappingException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		} catch (IOException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		}
		String json = writer.toString();
		try {
			writer.close();
		} catch (IOException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		}
		writer = null;
		return json;

	}

	// 无法确定 <T>T 的类型参数；对于上限为 T,java.lang.Object 的类型变量 T,不存在唯一最大实例
	public static <T> T unmarshal(String json, Class<T> clazz) {
		try {
			return (T) objectMapper.readValue(json, clazz);
		} catch (JsonParseException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		} catch (JsonMappingException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		} catch (IOException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public static <T> T unmarshalList(String json, Class<?> clazz) {
		try {
			return (T) objectMapper.readValue(json, TypeFactory.collectionType(ArrayList.class, clazz));
		} catch (JsonParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JsonMappingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public static <T> T unmarshal(String json, TypeReference<T> typeReference) {
		try {
			return (T) objectMapper.readValue(json, typeReference);
		} catch (JsonParseException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		} catch (JsonMappingException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		} catch (IOException e) {
			// ExceptionUtils.write(e,writer);
			e.printStackTrace();
			// TODO log
		}
		return null;
	}
}
